package com.stk.dots;

import java.util.ArrayList;
import java.util.Random;

import com.stk.dots.GraphicObject.Speed;
import com.stk.dots.SurfaceThread.Status;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.Button;

class Panel extends SurfaceView implements SurfaceHolder.Callback {
	
	public static final int OFF_SPEED = 5;
	public static final int MAX_TOUCHPOINTS = 10;
	public static final int MAX_PUN = 50000;
	public static final int EASY = 20;
	public static final int MEDIUM = 10;
	public static final int HARD = 4;

	
	private SurfaceThread _thread;
	private ArrayList<GraphicObject> _graphics = new ArrayList<GraphicObject>();
	private Random _random = new Random();
	private int _punctuation = 0;
	private long _gameTimeOut = 0;
	private long _pauseTimeOut = 0;
	private int _difficulty = EASY; //set easy as default for avoiding problems
	
	private Button _button;

	
	public Panel(Context context){
		super(context);
		getHolder().addCallback(this);
		_thread = new SurfaceThread(getHolder(), this);
		setFocusable(true);
		setFocusableInTouchMode(true);
		
		 _button = new Button(context);      
	     _button.measure(50, 50);
	     
	     int width = _button.getMeasuredWidth();
	     int height = _button.getMeasuredHeight();
	     int left = 60; 
	     int top = 60;
	           
	     _button.layout(left, top, left + width, top + height);
	}
	
	public void drawGame(Canvas canvas){
		canvas.drawColor(Color.BLACK);
		if (_gameTimeOut < 3000){
			Paint paint = new Paint();
			String text = "READY";
			
			paint.setARGB(255,255,255,255);
			paint.setTextSize(50);
			
			if (_gameTimeOut < 1000){
				text = "READY";
			}else if (_gameTimeOut < 2000){
				text = "STEADY";
			}else if (_gameTimeOut < 3000){
				text = "GO!";
			}
			
			canvas.drawText(text, getWidth()/2, getHeight()/2, paint);
		}else{
			GraphicObject.Coordinates coords;
			GraphicObject.Life life;
			Paint paint = new Paint();
			for (GraphicObject graphic : _graphics) {
				coords = graphic.getCoordinates();
				life = graphic.getLife();

				//Paint OUTSIDE circle
				paint.setARGB(graphic.getCircleColor().getAlpha(),
						110,
						110,
						110);
				paint.setAntiAlias(true);
				canvas.drawCircle(coords.getX(), coords.getY(), coords.getRadius() + 2, paint);

				//Paint INNER circle
				paint.setARGB(graphic.getCircleColor().getAlpha(),
						graphic.getCircleColor().getRed(),
						graphic.getCircleColor().getGreen(),
						graphic.getCircleColor().getBlue());
				paint.setAntiAlias(true);	        
				canvas.drawCircle(coords.getX(), coords.getY(), coords.getRadius(), paint);      

				//Draw the Strings inside the Circle
				paint.setARGB(255,0,0,0);
				paint.setTextSize(20);
				if (life.getTimeElapsed()/1000 < 1){
					canvas.drawText("0." +  String.valueOf(life.getTimeElapsed()).substring(0,1), coords.getX()-13, coords.getY()+5, paint);
				}else{
					canvas.drawText(String.valueOf(life.getTimeElapsed()/1000)+ "." +  String.valueOf(life.getTimeElapsed()).substring(1, 2), coords.getX()-13, coords.getY()+5, paint);
				}

			}
			//Draw rectangle for punctuation
			if (_punctuation >= 0 ){
				paint.setARGB(255, 0, 255, 0);
				canvas.drawRect(new RectF(getWidth()/2, 0, (getWidth()/2) + (((getWidth()/2)* _punctuation) / MAX_PUN), 3), paint);
			}else{
				paint.setARGB(255, 255, 0, 0);
				canvas.drawRect(new RectF((getWidth()/2) + (((getWidth()/2)* _punctuation) / MAX_PUN), 0, getWidth()/2, 3), paint);
			}
		}

	}
	
	public void drawMenu(Canvas canvas){
		canvas.drawColor(Color.BLACK);
		
		Paint paint = new Paint();
		//Draw the Strings left -> GAME right -> INSTRUCTIONS
		paint.setARGB(255,255,255,255);
		paint.setTextSize(20);
		canvas.drawText("GAME", 0, getHeight()/2, paint);
		canvas.drawText("INSTRUCTIONS", getWidth()/2, getHeight()/2, paint);
	}	
	
	public void drawInstructions(Canvas canvas){
		canvas.drawColor(Color.BLACK);
		
		Paint paint = new Paint();
		//Draw instructions strings
		paint.setARGB(255,255,255,255);
		paint.setTextSize(20);
		canvas.drawText("CLICK EVERY CIRCLE BEFORE THEY GET RED AND FILL GREEN BAR ;D", 0, getHeight()/2, paint);
	}
	
	public void drawPaused(Canvas canvas){
		Paint paint = new Paint();
		paint.setARGB(50,0,0,0);
		canvas.drawRect(new RectF(0, 0, getWidth(), getHeight()), paint);
		
		paint.setARGB(255,255,255,255);
		paint.setTextSize(20);
		canvas.drawText("PAUSED!", 100, 100, paint);
		canvas.drawText("Touch the screen for continue", 100, 170, paint);
		canvas.drawText("Press back key to go to menu", 100, 240, paint);
	}
	
	public void drawLevelSelection(Canvas canvas){
		canvas.drawColor(Color.BLACK);
		
		Paint paint = new Paint();
		//Draw the Strings Top->EASY, Mid->NORMAL, Bot->HARD
		paint.setARGB(255,255,255,255);
		paint.setTextSize(20);
		canvas.drawText("EASY", getWidth()/2, (getHeight()/3)/2, paint);
		canvas.drawText("MEDIUM", getWidth()/2, ((getHeight()/3)/2) + (getHeight()/3), paint);
		canvas.drawText("HARD", getWidth()/2, ((getHeight()/3)/2) + ((getHeight()/3) * 2), paint);
		
	}
	
	public void drawWin(Canvas canvas, long totalTime){
		canvas.drawColor(Color.BLACK);
		
		_button.draw(canvas);
		
		Paint paint = new Paint();
		//Draw the Strings Top->EASY, Mid->NORMAL, Bot->HARD
		paint.setARGB(255,255,255,255);
		paint.setTextSize(20);
		canvas.drawText("YOU WON!!!", getWidth()/2, 100, paint);
		canvas.drawText((String.valueOf(totalTime/1000)) + "." + (String.valueOf(totalTime%1000)) + "   SECONDS!", getWidth()/2, 200, paint);
		canvas.drawText("REALLY GOOD TIME FOR A CHIMP!!", 0, 230, paint);
		canvas.drawText("back key for menu", 0, 270, paint);
	}
	
	public void drawLoose(Canvas canvas, long totalTime){
		canvas.drawColor(Color.BLACK);
		
		_button.draw(canvas);
		
		Paint paint = new Paint();
		//Draw the Strings Top->EASY, Mid->NORMAL, Bot->HARD
		paint.setARGB(255,255,255,255);
		paint.setTextSize(20);
		canvas.drawText("YOU ARE A LOOSER!!!", getWidth()/2, 100, paint);
		canvas.drawText((String.valueOf(totalTime/1000)) + "." + (String.valueOf(totalTime%1000)) + "   SECONDS!", getWidth()/2, 200, paint);
		canvas.drawText("SO MANY TIME FOR LOOSING?", 0, 230, paint);
		canvas.drawText("back key for menu", 0, 270, paint);
	}

    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        // TODO Auto-generated method stub
    }
 

    public void surfaceCreated(SurfaceHolder holder) {
        _thread.setRunning(true);
        _thread.start();
    }
 

    public void surfaceDestroyed(SurfaceHolder holder) {
        boolean retry = true;
        _thread.setRunning(false);
        while (retry){
        	try{
        		_thread.join();
        		retry = false;
        	} catch (InterruptedException e){
        		//try again
        	}           	    		
        }
    }
    
    // Delete graphic on touch, if touched on a circle delete it
    /**
     * TOUCH EVENTS
     * -PLAYING
     * -MENU
     * -INSTRUCTIONS
     * -PAUSED
     * -LEVEL_SELECT
     */
    public boolean onTouchEvent (MotionEvent event){
    	synchronized (_thread.getSurfaceHolder()) {
    		switch (_thread.getStatus()){

    		case PLAYING:{
    			int pointerCount = event.getPointerCount();
    			if (pointerCount > MAX_TOUCHPOINTS) {
    				pointerCount = MAX_TOUCHPOINTS;
    			}
    			if (event.getActionMasked() == MotionEvent.ACTION_DOWN || event.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN) {            	
    				int id = event.getActionIndex();
    				boolean found = false;
    				int i = _graphics.size() - 1;
    				while ((i>=0)&&(!found)){
    					GraphicObject graphic = _graphics.get(i);
    					GraphicObject.Coordinates coord = graphic.getCoordinates();
    					GraphicObject.Speed speed = graphic.getSpeed();
    					int distance;                  
    					//Check distance between points
    					distance = (int) Math.sqrt(Math.pow((coord.getX() - event.getX(id)),2) + Math.pow((coord.getY() - event.getY(id)), 2));
    					//If distance is smaller than the circle radius, DECREASE
    					if (distance <= coord.getRadius()){
    						if (speed.getBehaviour() == Speed.INCREASE){
    							speed.toggleBahaviour();
    							speed.setRadiusSpeed(OFF_SPEED);
    							_punctuation += graphic.getLife().getTimeElapsed();
    							graphic.getCircleColor().setColors(255, 0, 255, 0);
    							found = true;
    						} 
    					}
    					i--;
    				}
    			}
    		}break;

    		case MENU:{     			
    			if (event.getAction() == MotionEvent.ACTION_DOWN){
    				if (event.getX() <= getWidth()/2){    					
    	    			//all start with current time for not having errors during initialization
    	    			_thread.setStatus(Status.LEVEL_SELECT);
    				}else{
    					//Show instructions
    					_thread.setStatus(Status.INSTRUCTIONS);
    				}
    			}
    		}break;
    		
    		case INSTRUCTIONS:{
    			if (event.getAction() == MotionEvent.ACTION_DOWN){
    				//Back to menu
    				_thread.setStatus(Status.MENU);
    			}
    		}break;
    		
    		case PAUSED:{
    			if (event.getAction() == MotionEvent.ACTION_DOWN){
    				//Back to playing, add spent time in pause to startTime for having a real total time played
	    			_thread.setStartTime(_thread.getStartTime() + _pauseTimeOut);
	    			_thread.setStatus(Status.PLAYING);    				
    			}
    		}break;
    		
    		case LEVEL_SELECT:{
    			if (event.getAction() == MotionEvent.ACTION_DOWN){    				
    				if (event.getY() <= getWidth()/3){    					
    					//set game to EASY
    					resetGameTimeOut();
    					_difficulty = EASY;
    				}else if ((event.getY() > getWidth()/3) && (event.getY() <= (getWidth()/3)*2)){
    					//set game to MEDIUM
    					resetGameTimeOut();
    					_difficulty = MEDIUM;    					
    				}else if ((event.getY() <= getWidth()) && (event.getY() > (getWidth()/3)*2)){
    					//set game to MEDIUM
    					resetGameTimeOut();
    					_difficulty = HARD;    					
    				}
    				resetGameTimeOut();
    				resetGame();
    				_thread.setStartTime(android.os.SystemClock.elapsedRealtime());
					_thread.setStatus(Status.PLAYING);
    			}
    		}break;
    		}

    	}         
    	return true;  
    }
    /**
     * BACK KEY
     * -PLAYING
     * -INSTRUCTION
     * -PAUSED
     * -LEVEL_SELECT
     * -WIN
     * -LOOSE
     * -MENU
     */
    
    /**
     * MENU KEY
     * -PLAYING
     */
    public boolean onKeyDown(int keyCode, KeyEvent event){
    	synchronized (_thread.getSurfaceHolder()) {
    		if ((keyCode == KeyEvent.KEYCODE_BACK) && (event.getAction() == KeyEvent.ACTION_DOWN)){
    			switch (_thread.getStatus()){
    			case PLAYING:{
        				//Pause ON
        				resetPauseTimeOut();
        				_thread.setStatus(Status.PAUSED);
        		}break;
        		
        		case INSTRUCTIONS:{
        				//Back to menu
        				_thread.setStatus(Status.MENU);
        		}break;
        		
        		case PAUSED:{
        			//Back to menu        			    				
    	    		resetPauseTimeOut();
    	    		_thread.setStatus(Status.MENU);
        		}break;
        		
        		case LEVEL_SELECT:{
        			//Back to menu
    				_thread.setStatus(Status.MENU);
        		}break;
        		
        		case WIN:{
        			//Back to menu
    				_thread.setStatus(Status.MENU);
        		}break;
        		
        		case LOOSE:{
        			//Back to menu
    				_thread.setStatus(Status.MENU);
        		}break;
        		
        		case MENU:{     			
        			return false;
        		}
    			}
			}else if ((keyCode == KeyEvent.KEYCODE_MENU) && (event.getAction() == KeyEvent.ACTION_DOWN)){
				switch (_thread.getStatus()){
				case PLAYING:{
	    				//Pause ON
	    				resetPauseTimeOut();
	    				_thread.setStatus(Status.PAUSED);
	    		}break;
				}
			}
    		
    	}
    	return true;
    }

    
    public void updateGame(long elapsedTime) {
    	if (_gameTimeOut < 3000){
    		//Increase timeOut time for RSG
    		_gameTimeOut += elapsedTime;
    	}else{
    		//Update circles
    		GraphicObject.Coordinates coord;
    		GraphicObject.Speed speed;
    		GraphicObject.Life life;
    		ArrayList<GraphicObject> toDelete = new ArrayList<GraphicObject>();

    		for (GraphicObject graphic : _graphics) {
    			coord = graphic.getCoordinates();
    			speed = graphic.getSpeed();
    			life = graphic.getLife();

    			// Direction            
    			coord.setRadius(coord.getRadius() + (speed.getRadiusSpeed() * speed.getBehaviour()));

    			//Update Life of circles
    			if (speed.getBehaviour() == Speed.INCREASE){
    				life.increaseTime(elapsedTime);
    			}


    			//Check if life is over and set as DECREASE
    			if (!life.checkLife()){
    				if (speed.getBehaviour() == Speed.INCREASE){
    					_punctuation -= life.getTimeElapsed();
    					speed.toggleBahaviour();
    					speed.setRadiusSpeed(OFF_SPEED);
    					graphic.getCircleColor().setColors(255, 255, 0, 0);
    				}        		
    			}

    			//Check if size is bellow 0 so we have to delete it
    			if (coord.getRadius()<=0){
    				toDelete.add(graphic);
    			}
    		}


    		//Delete the finished circles
    		if (!_graphics.isEmpty()){
    			_graphics.removeAll(toDelete);
    			toDelete.clear();
    		}
    		
    		//Add circles if random number is equal level
    		if (_random.nextInt(_difficulty)== (int) (_difficulty/2)){
        		_graphics.add(new GraphicObject(_random, getWidth(), getHeight(), 20));
        	}
    		
    		if (Math.abs(_punctuation) >= MAX_PUN){
    			endGame(_punctuation);
    		}
    	}
    }
    
    public void updatePause(long elapsedTime) {
    	_pauseTimeOut += elapsedTime;
    }

    public void resetGameTimeOut (){
    	_gameTimeOut = 0;
    }
    
    public void resetPauseTimeOut (){
    	_pauseTimeOut = 0;
    }
    
    public void resetGame (){
    	_punctuation = 0;
    	_graphics.clear();
    }
    
    public void endGame(int points){
    	_thread.setFinishTime(android.os.SystemClock.elapsedRealtime());
    	if (points >= 0){
			_thread.setStatus(Status.WIN);
    	}else{
    		_thread.setStatus(Status.LOOSE);
    	}
    }
}
